﻿using System;
using System.Collections.Generic;
using System.Reflection;
using System.Text.RegularExpressions;
using Neo4jRestSharp.Neo4jObjectServices;
using Neo4jRestSharp.Neo4jRestServices;
using Newtonsoft.Json.Linq;

namespace Neo4jRestSharp.Neo4jJsonServices
{
    /// <summary>
    /// Rest API for Neo4j as specified at (http://components.neo4j.org/neo4j-rest/)
    /// </summary>
    public class NodeJsonServices
    {
        private readonly Uri uri;
        private NodeRestServices restServices;

        public NodeJsonServices(Uri uri)
        {
            this.uri = uri;
            this.restServices = new NodeRestServices(uri);
        }

        #region Nodes and Node Properties
        /// <summary>
        /// Get root node
        /// </summary>
        /// <remarks>
        /// Http Success Response: 200 (a-ok)
        /// </remarks>
        public JObject GetRootNode()
        {
            string json = restServices.GetRootNode();
            JObject jObject = JObject.Parse(json);            
            return jObject;
        }

		/// <summary>
		/// Create node
		/// </summary>
		/// <remarks>
		/// Http Success Response: 201 (node was created)
		/// Http Error Response: 400 (invalid data sent)
		/// </remarks>
		public JObject CreateNode()
		{			
			string json = restServices.CreateNode();
			JObject jObject = JObject.Parse(json);
			return jObject;
		}

        /// <summary>
        /// Create node
        /// </summary>
        /// <remarks>
        /// Http Success Response: 201 (node was created)
        /// Http Error Response: 400 (invalid data sent)
        /// </remarks>
        public JObject CreateNode(JToken nodeParms)
        {
            string jsonParms = nodeParms.ToString();
            string json = restServices.CreateNode(jsonParms);
            JObject jObject = JObject.Parse(json);
            return jObject;                       
        }

        /// <summary>
        /// Get node by id
        /// </summary>
        /// <remarks>
        /// Http Success Response: 200 (a-ok)
        /// Http Error Response: 404 (node not found)
        /// </remarks>
        public JObject GetNode(int nodeId)
        {
            string json = restServices.GetNode(nodeId);
            JObject jObject = JObject.Parse(json);
            return jObject;
        }

        /// <summary>
        /// Set properties on node
        /// </summary>
        /// <remarks>
        /// Http Success Response: 204 (ok, no content returned)
        /// Http Error Response: 400 (invalid data sent)
        /// Http Error Response: 404 (node not found)
        /// </remarks>
        public void SetNodeProperties(int nodeId, JToken nodeParms)
        {
            string jsonParms = nodeParms.ToString();
            restServices.SetNodeProperties(nodeId, jsonParms);            
        }

        /// <summary>
        /// Get properties on node
        /// </summary>
        /// <remarks>
        /// Http Success Response: 200 (a-ok)
        /// Http Success Response: 204 (ok, no properties found)
        /// Http Error Response: 404 (node not found)
        /// </remarks>
        public JObject GetNodeProperties(int nodeId)
        {
        	string json = restServices.GetNodeProperties(nodeId);
        	if (string.IsNullOrWhiteSpace(json))
        	{
        		return new JObject();
        	}

        	JObject jObject = JObject.Parse(json);
        	return jObject;
        }

    	/// <summary>
        /// Remove all properties on node
        /// </summary>
        /// <remarks>        
        /// Http Success Response: 204 (ok, no properties found)
        /// Http Error Response: 404 (node not found)
        /// </remarks>
        public void RemoveNodeProperties(int nodeId)
        {
            restServices.RemoveNodeProperties(nodeId);
        }

        /// <summary>
        /// Set property on node
        /// </summary>
        /// <remarks>
        /// Http Success Response: 204 (ok, no content returned)
        /// Http Error Response: 400 (invalid data sent)
        /// Http Error Response: 404 (node not found)
        /// </remarks>
        public void SetNodeProperty(int nodeId, string propertyName, string propertyValue)
        {
            restServices.SetNodeProperty(nodeId, propertyName, propertyValue);            
        }

        /// <summary>
        /// Get property on node
        /// </summary>
        /// <remarks>
        /// Http Success Response: 200 (a-ok)        
        /// Http Error Response: 404 (node or property not found)
        /// </remarks>
        public string GetNodeProperty(int nodeId, string propertyName)
        {
            return restServices.GetNodeProperty(nodeId, propertyName);            
        }

        /// <summary>
        /// Remove property on node
        /// </summary>
        /// <remarks>
        /// Http Success Response: 204 (a-ok)        
        /// Http Error Response: 404 (node or property not found)
        /// </remarks>
        public void RemoveNodeProperty(int nodeId, string propertyName)
        {
            restServices.RemoveNodeProperty(nodeId, propertyName);
        }     

        /// <summary>
        /// Delete node
        /// </summary>
        /// <remarks>
        /// Http Success Response: 204 (a-ok)        
        /// Http Error Response: 404 (node not found)
        /// Http Error Response: 409 (Node could not be deleted (still has relationships?))
        /// </remarks>
        public void DeleteNode(int nodeId)
        {
            restServices.DeleteNode(nodeId);
        }
        #endregion Nodes and Node Properties

        #region Node Relationships
        /// <summary>
        /// Create node relationship
        /// </summary>
        /// <remarks>
        /// Http Success Response: 201 (ok, relationship was created)        
        /// Http Error Response: 400 (invalid data sent)
        /// Http Error Response: 405 ("to" node, or the node specified by the URI not found)
        /// </remarks>
        public JObject CreateRelationship(int nodeId, JObject relationshipData)
        {
			string jsonIn = relationshipData.ToString();
			string jsonOut = restServices.CreateRelationship(nodeId, jsonIn);
        	JObject jObject = JObject.Parse(jsonOut);
        	return jObject;
        }

        /// <summary>
        /// Set properties on relationship
        /// Replaces all properties on a relationship with the supplied set of properties.
        /// </summary>
        /// <remarks>
        /// Http Success Response: 204 (a-ok, no content returned)        
        /// Http Error Response: 400 (invalid data sent)
        /// Http Error Response: 404 (relationship not found)
        /// </remarks>
		public void SetRelationshipProperties(int relationshipId, JToken relationshipData)
        {
			string json = relationshipData.ToString();
			restServices.SetRelationshipProperties(relationshipId, json);
        }

        /// <summary>
        /// Get properties on relationship
        /// </summary>
        /// <remarks>
        /// Http Success Response: 200 (a-ok)
        /// Http Success Response: 204 (a-ok, no relationships found)
        /// Http Error Response: 404 (relationship not found)
        /// </remarks>
		public JObject GetRelationshipProperties(int relationshipId)
        {
        	string json = restServices.GetRelationshipProperties(relationshipId);
			if (string.IsNullOrWhiteSpace(json))
			{
				return new JObject();
			}
			JObject jObject = JObject.Parse(json);
			return jObject;        	
        }

        /// <summary>
        /// Remove all properties on relationship
        /// </summary>
        /// <remarks>
        /// Http Success Response: 204 (a-ok, no content returned)        
        /// Http Error Response: 404 (relationship not found)
        /// </remarks>
		public void RemoveRelationshipProperties(int relationshipId)
        {
            restServices.RemoveRelationshipProperties(relationshipId);
        }

        /// <summary>
        /// Set a single property on relationship        
        /// </summary>
        /// <remarks>
        /// Http Success Response: 204 (a-ok, no content returned)        
        /// Http Error Response: 400 (invalid data sent)
        /// Http Error Response: 404 (relationship not found)
        /// </remarks>
        public void SetRelationshipProperty()
        {
            throw new NotImplementedException();
        }

        /// <summary>
        /// Get a single property relationship
        /// </summary>
        /// <remarks>
        /// Http Success Response: 200 (a-ok)
        /// Http Error Response: 404 (relationship not found)
        /// </remarks>
        public void GetRelationshipProperty()
        {
            throw new NotImplementedException();
        }

        /// <summary>
        /// Remove a single property on relationship        
        /// </summary>
        /// <remarks>
        /// Http Success Response: 204 (a-ok, no content returned)        
        /// Http Error Response: 404 (relationship or property not found)
        /// </remarks>
        public void RemoveRelationshipProperty()
        {
            throw new NotImplementedException();
        }

        /// <summary>
        /// Delete relationship        
        /// </summary>
        /// <remarks>
        /// Http Success Response: 204 (a-ok, no content returned)        
        /// Http Error Response: 404 (relationship not found)
        /// </remarks>
		public void RemoveRelationship(int relationshipId)
        {
			restServices.RemoveRelationship(relationshipId);
        }

        /// <summary>
        /// Get relationships on node
        /// </summary>
        /// <remarks>
        /// Http Success Response: 200 (a-ok, no content returned)        
        /// Http Error Response: 404 (node not found)
        /// </remarks>
		public JArray GetRelationshipsOnNode(int nodeId, RelationshipDirection relationshipDirection, IEnumerable<string> relationshipTypes)
        {
        	string json = restServices.GetRelationshipsOnNode(nodeId, relationshipDirection, relationshipTypes);
        	JArray jArray = JArray.Parse(json);
        	return jArray;
        }
        #endregion Node Relationships

        #region Neo4j Indexes
        /// <summary>
        /// Get indexes
        /// </summary>
        /// <remarks>
        /// Http Success Response: 200 (a-ok, no content returned)        
        /// </remarks>
        public void GetIndexes()
        {
            throw new NotImplementedException();
        }

        /// <summary>
        /// Add to index
        /// </summary>
        /// <remarks>
        /// Http Success Response: 201 (a-ok, indexed the node with key/value)
        /// </remarks>
        public void AddToIndex()
        {
            throw new NotImplementedException();
        }

        /// <summary>
        /// Remove from index
        /// </summary>
        /// <remarks>
        /// Http Success Response: 204 (a-ok, no content returned)
        /// Http Error Response: 404 (index entry not found)
        /// </remarks>
        public void RemoveFromIndex()
        {
            throw new NotImplementedException();
        }

        /// <summary>
        /// Query index
        /// </summary>
        /// <remarks>
        /// Http Success Response: 200 (a-ok, no content returned)
        /// Http Error Response: 404 (index entry not found)
        /// </remarks>
        public void QueryIndex()
        {
            throw new NotImplementedException();
        }
        #endregion Neo4j Indexes

        #region Neo4j Graph Traverses
        /// <summary>
        /// Traverse graph
        /// </summary>
        /// <remarks>
        /// Http Success Response: 200 (a-ok, no content returned)
        /// Http Error Response: 404 (node not found)
        /// </remarks>
        public void TraverseGraph()
        {
            throw new NotImplementedException();
        }
        #endregion Neo4j Graph Traverses
	}
}
